package com.ysp.summary.designpattern.simplefactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.DriverManager;
import java.util.Calendar;

/**
 * 简单工厂模式 : 因创建实例的方法是静态方法，因此简单工厂模式又被称为静态工厂方法模式（属于类创建模式，不属于GOF23种设计模式）
 *
 * 工厂类实现的两种方法：使用 if-else判断和使用反射来创建对象
 *
 * 最终实现：客户端传参就好了   具体的创建对象的逻辑交给了工厂类来完成
 *
 * 优点： 实现了对象 创建和试用的分离
 * 不需要知道具体产品的类名  只需要知道具体产品类所对应的参数即可 对于如何创建对象并不关心
 *
 * 缺点：集中了所有产品的创建逻辑，职责过重  一旦不能正常工作 整个系统都会有影响   引入了工厂类  增加了系统的复杂度和理解难度
 * 系统扩展困难  一旦增加了新的产品就不得不修改工厂逻辑 产品较多时，造成工厂逻辑过于复杂
 * 使用了静态工厂方法，造成工厂角色无法形成基于继承的等级结构
 *
 * 典型应用及源码分析:
 *      Calendar 类获取日历类对象
 *      JDBC 获取数据库连接
 *      LoggerFactory 获取 Logger 对象
 *
 * @author Administrator
 */
public class SimpleFactory {


    /**
     * 简单工厂获取对象实例的方法 必须是静态的   创建对象的逻辑 交给工厂来负责
     *
     * 通过   if-else  判断实现
     * @param type
     * @return
     */
    public static People getPeople(String type){
        if ("stu".equals(type)){
            return new People.Student();
        }else if("tec".equals(type)){
            return new People.Teacher();
        }else {
            return null;
        }
    }

    /**
     * 使用反射来创建对象实例  静态的实例方法
     * @param c
     * @return
     */
    public static People getPeople(Class<?> c){
        People people = null;
        try {
//            c.getSimpleName().toLowerCase();
            people = (People)Class.forName(c.getName()).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return people;
    }


    /**
     * 测试一下  工厂能不能生产出东西
     * @param args
     */
  public static void main(String[] args) throws Exception{
//    SimpleFactory factory = new SimpleFactory();
    People student = SimpleFactory.getPeople("stu");
    System.out.println("使用if-else工厂创建："+student);
    student.work();
    People student1 = SimpleFactory.getPeople(People.Student.class);
    System.out.println("使用反射工厂创建："+student1);
    student1.work();

    //使用举例


      /**
       * 抽象的产品角色和工厂角色 都是 Calendar 担任
       */
      Calendar calendar = Calendar.getInstance();

      /**
       * 数据库 jdbc  还记得吗
       * 通过反射加载驱动类  在通过驱动管理获取数据库连接
       * 看看 com.mysql.jdbc.Driver 的代码，该类主要的内容是静态代码块，其会随着类的加载一块执行
       * 静态代码块：new 一个 Driver 类并注册到 DriverManager 驱动管理类中
       *  registeredDrivers 是一个 CopyOnWriteArrayList 对象
       * CopyOnWriteArrayList是Java并发包中提供的一个并发容器，它是个线程安全且读操作无锁的ArrayList，写操作则通过创建底层数组的新副本来实现，
       * 是一种读写分离的并发策略，我们也可以称这种容器为”写时复制器”，Java并发包中类似的容器还有CopyOnWriteSet
       * 再通过 DriverManager.getConnection 获取连接对象的主要代码如下：通过for循环从已注册的驱动中(registeredDrivers)获取驱动，尝试连接，成功则返回连接
       * 工厂角色为 DriverManager 类，抽象产品角色为 Connection，具体产品角色则很多
       */
      Class.forName("com.mysql.cj.jdbc.Driver");
      DriverManager.getConnection("jdbc:mysql:localhost:3306/test","root","123");

      /**
       * Logback 中的 LoggerFactory 获取 Logger 对象
       * 工厂角色为 iLoggerFactory 接口的子类如 LoggerContext，抽象产品角色为 Logger，具体产品角色为 Logger 的子类，主要是 NOPLogger 和 Logger 类
       */
      Logger logger = LoggerFactory.getLogger(SimpleFactory.class);
  }
}
